/**
 * @file mybutton.h
 * @brief
 *
 * 
 *
 * @author 1823419256@qq.com
 * @version 1.0
 * @date 2011
*/

#ifndef MYBOOK_CTRLS_MYBOOK_H_
#define MYBOOK_CTRLS_MYBOOK_H_

// CMyButton

typedef CWinTraits<WS_CHILD | WS_VISIBLE | BS_OWNERDRAW> SkinButtonTraits;

class CMyButton
	: public CWindowImpl<CMyButton, CWindow, SkinButtonTraits>
	, CMouseHover<CMyButton>
{
public:
	DECLARE_WND_SUPERCLASS(NULL, CButton::GetWndClassName())

	CMyButton() : m_bTracking(false), m_bButtonDown(false), 
		m_pImageList(NULL), m_iImageCount(0)
	{
		m_crFace = RGB(0x3E, 0x63, 0x7C);
		m_crBack = RGB(0xFF, 0xFF, 0xFF);
		m_crSelected = RGB(0xFF, 0xFF, 0xFF);
		m_crDisabled = RGB(0x87, 0x9F, 0xB0);

		if (NULL == m_fontText)
			m_fontText.Attach(AtlGetDefaultGuiFont());
	}

	~CMyButton()
	{
		m_fontText.DeleteObject();
	}
		
	CMyButton& operator=(const HWND& hControl)
	{
		this->SubclassWindow(hControl);
		this->ModifyStyle(0, SkinButtonTraits::GetWndStyle(0));

		return *this;
	}

	void ApplySkin(const CMyImage* pImageList, int iImageCount)
	{
		ATLASSERT(pImageList != NULL && iImageCount > 0);

		m_pImageList = (CMyImage *)pImageList;
		m_iImageCount = iImageCount;

		RECT rcWnd = { 0, 0, m_pImageList->GetWidth() / m_iImageCount, m_pImageList->GetHeight() };
		SetWindowPos(NULL, &rcWnd, SWP_NOZORDER | SWP_NOMOVE);
	}

	BEGIN_MSG_MAP(CMyButton)
		CHAIN_MSG_MAP(CMouseHover<CMyButton>)
		MESSAGE_HANDLER(OCM_DRAWITEM, OnDrawItem)
		MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
		MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
		MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
		MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
		MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseEnter)
		MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave)
		MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)
	END_MSG_MAP()

	LRESULT OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		if (m_pImageList == NULL)
		{
			bHandled = FALSE;
			return 0;
		}

		return 1;
	}

	LRESULT OnDrawItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		if (m_pImageList == NULL)
		{
			bHandled = FALSE;
			return 0;
		}

		LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam;
		CRect rect(lpdis->rcItem.left, lpdis->rcItem.top, lpdis->rcItem.right, lpdis->rcItem.bottom);
		CMemoryDC dc(lpdis->hDC, rect);

		RECT rcDraw = { rect.left, rect.top, 
			rect.left + m_pImageList->GetWidth() / m_iImageCount, 
			rect.top + m_pImageList->GetHeight() };

		BOOL bDrawBack = TRUE;
		DWORD dwTextColor = m_crFace;

		UINT itemState = lpdis->itemState;
		if (itemState & ODS_DISABLED && m_iImageCount >= 4)
		{
			MyDrawImagePart(dc, rcDraw, *m_pImageList, 3, m_iImageCount);
			dwTextColor = m_crDisabled;
		}
		else if (itemState & ODS_SELECTED && m_iImageCount >= 3)
		{	
			MyDrawImagePart(dc, rcDraw, *m_pImageList, 2, m_iImageCount);
			dwTextColor = m_crSelected;
			bDrawBack = FALSE;
		}
		else
		{
			if (m_bTracking && m_iImageCount >= 2)
			{
				MyDrawImagePart(dc, rcDraw, *m_pImageList, 1, m_iImageCount);
			}
			else
			{
				MyDrawImagePart(dc, rcDraw, *m_pImageList, 0, m_iImageCount);
			}
		}

		CRect rcBack(rcDraw);
		rcBack.OffsetRect(0, 1);

		CString strText;
		GetWindowText(strText);

		dc.SetBkMode(TRANSPARENT);
		dc.SelectFont(m_fontText);

		if (bDrawBack)
		{
			dc.SetTextColor(m_crBack);
			::DrawText(dc, strText, -1, &rcBack, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
		}

		dc.SetTextColor(dwTextColor);
		::DrawText(dc, strText, -1, &rcDraw, DT_SINGLELINE | DT_CENTER | DT_VCENTER);

		return 0;
	}

	LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		m_bButtonDown = true;
		bHandled = false;

		return 0;
	}

	LRESULT OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		m_bButtonDown = false;
		bHandled = false;

		return 0;
	}

	LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		if ((m_bButtonDown) && (::GetCapture() == m_hWnd))
		{
			POINT p2 = { LOWORD(lParam), HIWORD(lParam) };
			::ClientToScreen(m_hWnd, &p2);
			HWND hHotWnd = ::WindowFromPoint(p2);

			bool Pressed = ((GetState() & BST_PUSHED) == BST_PUSHED);
			bool bNeedPressed = (hHotWnd == m_hWnd);
			if (Pressed != bNeedPressed)
			{
				SetState(bNeedPressed ? TRUE : FALSE);
				Invalidate();
			}
		}

		bHandled = FALSE;

		return 0;
	}

	LRESULT OnMouseEnter(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		m_bTracking = true;
		Invalidate();

		return 0;
	}

	LRESULT OnMouseLeave(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		m_bTracking = false;
		Invalidate();

		return 0;
	}

	LRESULT OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		if (::GetCapture() == m_hWnd)
		{
			::ReleaseCapture();
			m_bButtonDown = false;
		}

		bHandled = FALSE;

		return 0;
	}

protected:
	UINT GetState() const
	{
		return (UINT)::SendMessage(m_hWnd, BM_GETSTATE, 0, 0L);
	}

	void SetState(BOOL bHighlight)
	{
		::SendMessage(m_hWnd, BM_SETSTATE, bHighlight, 0L);
	}

protected:
	BOOL m_bTracking;
	BOOL m_bButtonDown;

	CMyImage* m_pImageList;
	int m_iImageCount;

	CFont m_fontText;

	DWORD m_crFace;
	DWORD m_crBack;
	DWORD m_crSelected;
	DWORD m_crDisabled;
};

#endif // MYBOOK_CTRLS_MYBOOK_H_